sass VS less

为了重构项目的css代码,先体验了less,但发现less不能满足我的需求,没办法转为sass,在此描述一下自我感受这两者的区别。我描述的只是我直观使用的部分,大部分的不同点百度一下,第一页的全一样。。。

判断条件的区别(感觉最重要的地方)

  • lessmixin时判断的唯一关键字就是when,而我需要生成复合样式中的一部分,像这样:
    1
    2
    3
    4
    a{
    border-right:1px;
    border-bottom:2px;
    }

要选择性的生成部分属性,less很不方便,可以参考前面一篇文章less实战全解之复合样式mixin

  • sass的判断关键字很符合我们的习惯@if@else@else if,还有其他的@for@each,非常强大。额…有点跑题,继续。那么用sass处理符合属性可以写成这样,不会生成多余的属性:
    1
    2
    3
    4
    5
    6
    7
    8
    @mixin position($position,$top:null,$right:null,$bottom:null,$left:null,$z-index:null){
    position: $position;
    @if $top{top: $top;}
    @if $right{right: $right;}
    @if $bottom{bottom: $bottom;}
    @if $left{left: $left;}
    @if $z-index{z-index: $z-index;}
    }

假设要编译成这样的css:

1
2
3
position: absolute;
right: 0;
bottom: 0;

使用的方式有两种:

1
2
3
4
//方法1,最后一个"有效参数"前面的参数设为null,后面的不用管,因为参数默认值就是null
@include position(absolute,null,0,0);
//方法2,指定参数名称
@include position(absolute,$right:0,$bottom:0);

而且像sass写的这种:支持多属性的0%和100%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@mixin frames($props,$starts,$ends){
$length:length($props);
0% {
@for $i from 1 through $length{
$prop:nth($props,$i);
#{$prop}:nth($starts,$i);
}
}
100%{
@for $j from 1 through $length{
$prop:nth($props,$j);
#{$prop}:nth($ends,$j);
}
}
}

less由于缺少for这种关键字,只能通过递归实现循环,要实现上面的效果,想想就醉了

import的路径问题

  • less:可以使用相对路径和绝对路径,可以参考前面的文章
  • sass:可以使用相对路径,绝对路径好像不可以,我尝试了很多次,依旧不行,不知道是不是我尝试的有问题,请知道的前辈告诉我。语法没有less的小括号,如下:
    1
    @import "../../furnace/sass/_base";

使用mixin

  • less:只能放在选择器内,不能放在外面,以至于我只能这样定义一个动画,而不能使用公共mixin定义动画

    1
    2
    3
    4
    5
    6
    7
    .blink {
    .animation(blink 1.8s infinite);
    }
    @-webkit-keyframes blink {.keyframes-opacity(10,0);}
    @-moz-keyframes blink {.keyframes-opacity(10,0);}
    @-o-keyframes blink {.keyframes-opacity(10,0);}
    @keyframes blink {.keyframes-opacity(10,0);}
  • sass:可以放在外面,然后代码就变成了这样:

    1
    2
    3
    4
    .blink {
    @include animation(blink 1.8s infinite);
    }
    @include keyframes-opacity(blink);

是不是简练了很多?

内部函数

  • less:自定义函数比较多,很方便
  • sass:官方自己封装的都是基本的,比较少,如三角操作函数就没有,所以需要用sass扩展库:compasssassCore

编译

grunt插件编译

很多人选择用less是因为用sass是基于ruby的,所以选择了less,我在使用的过程中用了这样两个插件,都是grunt的,gulp当然也有。下面我的两个插件:

此处不使用grunt官方团队的grunt-contrib-sass,因为它需要ruby环境的支持

使用grunt-sass,就不需要安装ruby环境了,因为它是用node-sass编译的,只需要用npm安装了node-sass就可以编译了。这是我的Gruntfile.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
grunt.initConfig({
sass: {
dist:{
options: {
sourceMap: true,
outputStyle:"expanded"
},
dist:{
files:{
'sass/style.css':'sass/style.scss'
}
}
}
},
less:{
dist:{
options:{
// paths: ['WebRoot/css']//Directory of input file.
},
files:{
'WebRoot/css/less/tvwall.css':'WebRoot/css/less/tvwall.less'
}
}
},
watch:{
css:{
files:[
'WebRoot/css/less/tvwall.less',
'WebRoot/css/sass/tvwall.scss',
],
tasks:['less','sass'],
options:{
reload:true
}
},
self:{
files:['Gruntfile.js'],
tasks:['watch:css']
}
}
});
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['less','sass','watch']);

命令行使用:

1
grunt watch

js编译,方便调试

  • less是基于JavaScript,所以,是在客户端处理的。官方提供了less.js文件,放在html里直接就可以编译,很方便.
  • sass是基于服务端的,但有牛人创造了sass.js,主要由:sass.jssass.work.jssass.sync.js组成。如果你的浏览器支持h5的 Web Worker,请使用sass.jssass.work.js,我这儿就用的这两个文件。如果不支持,就使用sass.jssass.sync.js。使用如下:

(1)直接在html中使用sass.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="/js/sass/sass.js"></script>
<script>
var sass = new Sass('/js/sass/sass.worker.js');
sass.destroy();
var sass = new Sass();
sass.options({
style: Sass.style.expanded//这种格式我们比较习惯
});

var base = '../../furnace/';
var directory = '';
/*因为我的'audio.scss'引入了公共的文件:
* @import "../../sass/_base";
* 所以'_base.scss'文件也必须使用preloadFiles()"注册"文件之后再编译
*/
var files = [
'audio/sass/audio.scss',
'sass/_base.scss'
];
sass.preloadFiles(base, directory, files, function() {
sass.compileFile('audio/sass/audio.scss',function(result) {
var style=document.createElement('style');
style.innerHTML=result.text;
document.head.appendChild(style);
});
});
</script>
</head>
<body>
</body>
</html>

(2)在对应的模块js中使用
我们使用了sea.js来模块化,本来官方介绍是简单的require之后就可以使用,官方demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
define(function defineSassModule(require) {
// load Sass.js
var Sass = require('path/to/sass.js');
// tell Sass.js where it can find the worker,
// url is relative to document.URL - i.e. outside of whatever
// Require or Browserify et al do for you
Sass.setWorkerUrl('dist/sass.worker.js');
// initialize a Sass instance
var sass = new Sass();
var scss = '$someVar: 123px; .some-selector { width: $someVar; }';
sass.compile(scss, function(result) {
console.log(result);
});
});

但是在我的项目里并不成功,提示require返回的对象是underfined,注意到了sass.js里面的这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
(function (root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
/*走到了这个逻辑里,可能是因为用的是sea.js而非require.js*/
root.Sass = factory();
}
}(this,function(){...})
)

所以,require之后的对象被绑定到了window上,于是,代码修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
define(function(require, exports, module) {
require('/js/sass/sass.js');
Sass.setWorkerUrl(suninfo.getRootPath()+'js/sass/sass.worker.js');
var sass=new Sass();
sass.options({
style: Sass.style.expanded
});

var base = '../../furnace/';
var directory = '';
var files = [
'audio/sass/audio.scss',
'sass/_base.scss',
'sass/_variables.scss'
];
sass.preloadFiles(base, directory, files, function() {
sass.compileFile('audio/sass/audio.scss',function(result) {
var style=document.createElement('style');
style.innerHTML=result.text;
document.head.appendChild(style);
});
});
});

然后在浏览器中开心的调试sass吧…

最终,我还是比较喜欢sass。最后放个我总结的sass使用规范_base.scss:

堂 wechat
欢迎关注我的微信公众号,里面有各种小故事哦!
坚持原创技术分享,您的支持将鼓励我继续创作!